var https = require('https'),
    Promise  = require('bluebird'),
    accesstokenDao = require('../db/daos/accesstoken'),
    config = require('./configs');

/**
 * 获取适用于微信的(单位为秒, node的时间戳单位为毫秒), 当前时间的时间戳
 * @returns {number} 适用于微信的时间戳
 */
function getTimeStamp() {
  return Math.floor(Date.now() / 1000);
}

/**
 * 发送消息
 * FromUserName 消息发送方
 * ToUserName 消息接收方
 * CreateTime 消息创建时间
 * MsgType 消息类型，text
 * Content 消息内容
 */
function getTextMsg (FromUserName, ToUserName, msg) {
  var xmlMsg = '<xml><ToUserName>' + ToUserName +
    '</ToUserName><FromUserName>' + FromUserName +
    '</FromUserName><CreateTime>' + getTimeStamp() +
    '</CreateTime><MsgType>text</MsgType><Content>' +
    msg + '</Content></xml>';
  return xmlMsg;
}

/**
 * 将N个图文消息合并
 * @param {string} FromUserName
 * @param {string} ToUserName
 * @param {string[]} items 图文消息数组
 */
function getNewsMsg (FromUserName, ToUserName, items) {
  var strItems = '';
  items.map(function (item) {
    strItems = strItems + item;
  });
  var xmlMsg = '<xml>\
    <ToUserName><![CDATA[' + ToUserName + ']]></ToUserName>\
    <FromUserName><![CDATA[' + FromUserName + ']]></FromUserName>\
    <CreateTime>' + getTimeStamp() + '</CreateTime>\
    <MsgType><![CDATA[news]]></MsgType>\
    <ArticleCount>' + items.length + '</ArticleCount>\
    <Articles>' + items +
    '</Articles>\
  </xml> ';
  return xmlMsg;
}

/**
 * 获取一个图文消息
 * @param {string} title 标题
 * @param {string} description 描述
 * @param {string} picUrl 图片
 * @param {string} url 链接地址
 * @returns {string} xml格式的图文消息
 */
function getNewsItem (title, description, picUrl, url) {
  var xmlItemArr = ['<item>'];
  if (title) xmlItemArr.push('<Title><![CDATA[' + title + ']]></Title>');
  if (description) xmlItemArr.push('<Description><![CDATA[' + description + ']]></Description>');
  if (picUrl) xmlItemArr.push('<PicUrl><![CDATA[' + picUrl + ']]></PicUrl>');
  if (url) xmlItemArr.push('<Url><![CDATA[' + url + ']]></Url>');
  xmlItemArr.push('</item>');
  return xmlItemArr.join('');
}

/**
 * 获取进一步微信动作的access token
 * @param openid
 * @returns {*|exports|module.exports}
 */
function getAccessTokenFromWeixin(openid) {
  return new Promise(function (resolve, reject) {
    var resposeData = "";
    var appid  = config.appid;
    var secret = config.appsecret;
    var url    = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
    console.log('>>>>>> [Allspark].[INFO].getPlatformAccesstoken.url = ' + url);
    https.get(url, function (res) {
      if (res.statusCode == 200) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
          resposeData = chunk;
        });
        res.on("end", function () {
          var responseObject    = JSON.parse(resposeData);
          if (openid) {
            responseObject.openid = openid;
          }
          resolve(responseObject);
        });
      } else {
        reject();
        console.log("Get WeiXin Platform Access Token Fail.");
      }
    });
  });
}

/**
 * 发送POST请求到公众平台, 通过Promise获得返回值
 * @param api API uri path.例如: 'cgi-bin/qrcode/create?access_token=<TOKEN>'
 * @param accessToken
 * @param postData 请求的参数
 * @returns {Promise} API的返回值
 */
function apiPostRequest(api, accessToken, postData) {
  return new Promise(function (resolve, reject) {
    var api = 'cgi-bin/qrcode/create?access_token=' + accessToken.access_token,
        options = {
          hostname: 'api.weixin.qq.com',
          port    : 443,
          path    : api,
          method  : 'POST',
          headers : {
            'Content-Type': 'application/json; charset=UTF-8'
          }
        };
    var req = https.request(options, function (res) {
      var result = '';
      res.on('data', function (chunk) {
        result += chunk;
      });
      res.on('end', function () {
       resolve(result);
      });
    });
    req.on('error', function (err) {
      resolve(err);
    });
    req.write(postData);
    req.end();
  });
}

/**
 * 公众号的access token每2小时更新一次, 需定时刷新, 重复获取将导致上次获取的access_token失效
 * 每天可以获取2000次; 服务器需要自己保存access token 以免达到上限
 * 计算是否过期; 否: 直接返回access token; 否: 刷新access token再返回
 * @param openid{string | object} 希望向下传递的openid(string, 或者带有openid属性的对象)
 * @returns {Promise} access token
 */
function getAccessToken (openid) {
  if (typeof(openid) == 'object' && typeof(openid.openid) == 'string') {
    openid = openid.openid;
  } else if (typeof(openid) !== 'string') {
    openid = undefined;
  }
  return accesstokenDao.findOne().then(function (accessToken) {
    // 没有token或者token过期
    if (!accessToken || Date.now() - accessToken.create_time > config.access_token_expires_in) {
      return refreshAccessToken(openid);
    } else {
      if ('string' == typeof(openid)) accessToken.openid = openid;
      return Promise.resolve(accessToken);
    }
  });
}

/**
 *
 */
function refreshAccessToken(openid) {
  return Promise.resolve(getAccessTokenFromWeixin(openid)
    .then(function (accessToken) { // 取得token
      accessToken.create_time = getTimeStamp() * 1000;
      return accesstokenDao.upsert({}, accessToken)  // 更新数据库
        .then(accesstokenDao.findOne).then(function (at) {
          at.openid = openid; // 携带openid
          return Promise.resolve(at); // 返回查询结果
        });
    })
  );
}

/**
 * 获取用户信息, 必须先取得Accesstoken才能用这个方法
 * @param accessObject
 * @returns {*|exports|module.exports}
 */
function getUserInfo(openid) {
  return new Promise(function (resolve, reject) {
    var resposeData = "";
    getAccessToken(openid).then(function (accessObject) {
      var access_token = accessObject.access_token;
      var url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token + "&openid=" + openid;
      console.log('>>>>>> [Allspark].[INFO].getUserInfo.url = ' + url);
      https.get(url, function (res) {
        if (res.statusCode == 200) {
          res.setEncoding('utf8');
          res.on('data', function (chunk) {
            resposeData = chunk;
          });
          res.on("end", function () {
            var userInfoObject = JSON.parse(resposeData);
            if (!userInfoObject.errcode) {
              resolve(userInfoObject);
            } else {

              // 未认证的订阅号， 无法取得用户信息
              console.log("errcode : " + userInfoObject.errcode);
              console.log("errmsg : " + userInfoObject.errmsg);
              reject();
            }
          });
        } else {
          return Promise.reject();
          console.log("Get WeiXin User Info Fail.");
        }
      });
    });
  });
}

/**
 * 获取微信小店订单订单详情, 必须先取得Accesstoken才能用这个方法
 * @param orderId 订单ID
 * @returns {*|exports|module.exports}
 */
function getOrderById (orderId) {
  var host = 'api.weixin.qq.com',
      basePath = '/merchant/order/getbyid',
      params = {
        "order_id": orderId
      };
  return postRequestWithAccessToken(host, basePath, params);
}

function getRequestWithAccessToken(baseUrl, params) {
  return new Promise(function (resolve, reject) {
    var resposeData = "";
    getAccessToken().then(function (accessObject) {
      var access_token = accessObject.access_token;
      var url = baseUrl + "?access_token=" + access_token ;
      if (typeof params == 'object' && params !== null) {
        for (var property in params) {
          if (params.hasOwnProperty(property) && typeof params[property] == 'string') {
            url = url + "&" + property + "=" + params[property];
          }
        }
      }
      https.get(url, function (res) {
        if (res.statusCode == 200) {
          res.setEncoding('utf8');
          res.on('data', function (chunk) {
            resposeData = chunk;
          });
          res.on("end", function () {
            var receiveData = JSON.parse(resposeData);
            if (receiveData.errcode) {
              reject(receiveData);
            } else {
              resolve(receiveData);
            }
          });
        } else {
          reject();
        }
      });
    });
  });
}

function postRequestWithAccessToken(host, basePath, params) {
  return new Promise(function (resolve, reject) {
    getAccessToken().then(function (accessObject) {
      var api = basePath + '?access_token=' + accessObject.access_token,
          postData = JSON.stringify(params),
          options = {
            hostname: host,
            port    : 443,
            path    : api,
            method  : 'POST',
            headers : {
              'Content-Type': 'application/json; charset=UTF-8'
            }
          };
      var req = https.request(options, function (res) {
        var result = '';
        res.on('data', function (chunk) {
          result += chunk;
        });
        res.on('end', function () {
          resolve(result);
        });
      });
      req.on('error', function (err) {
        reject(err);
      });
      req.write(postData);
      req.end();
    });
  });
}
module.exports = {
  getTextMsg: getTextMsg,
  getTimeStamp: getTimeStamp,
  getNewsItem: getNewsItem,
  getNewsMsg: getNewsMsg,
  getAccessToken: getAccessToken,
  getUserInfo: getUserInfo,
  getOrderById: getOrderById
};
